<?php

namespace app\commands;

use app\extensions\webSocket\WebSocket;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * jump to the project root directory. run:
 * `./console ws:run {name}`
 * see help: `./console ws:run --help`
 * 命令行的参数是按位置赋予的
 */
class WsCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('ws:run')
            // 命令描述
            ->setDescription('Run the webSocket server.')
            // 配置第一个参数位置，参数名 name
            // 是可选的参数
            // 参数说明
            // ->addArgument(
            //     'name',
            //     InputArgument::OPTIONAL,
            //     'Who do you want to greet?'
            // )
            ->addOption(
               'ip',
               'i',
               InputOption::VALUE_OPTIONAL,
               'If set, the webSocket will use the IP.',
               '127.0.0.1'
            )
            ->addOption(
               'port',
               'p',
               InputOption::VALUE_OPTIONAL,
               'If set, the webSocket will use the port.',
               8880
            )
            ->addOption(
               'max-conn',
               null,
               InputOption::VALUE_OPTIONAL,
               'If set, the webSocket max connection limit.',
               10
            )
            ->addOption(
               'add-callback',
               null,
               InputOption::VALUE_OPTIONAL,
               'Setting the webSocket add callback name.',
               self::class . '::userAddCallback'
            )
            ->addOption(
               'send-callback',
               null,
               InputOption::VALUE_OPTIONAL,
               'Setting the webSocket send callback name.',
               self::class . '::sendCallback'
            )
            ->addOption(
               'close-callback',
               null,
               InputOption::VALUE_OPTIONAL,
               'Setting the webSocket close callback name.',
               self::class . '::closeCallback'
            )
        ;
    }

    protected $input;
    protected $output;

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->output = $output;

        $ip = $input->getOption('ip');
        $port = $input->getOption('port');
        $maxConn = $input->getOption('max-conn');

        $ws = new WebSocket($ip, $port, $maxConn);

        $ws->function['add']   = [$this, 'userAddCallback'];
        $ws->function['send']  = [$this, 'sendCallback'];
        $ws->function['close'] = [$this, 'closeCallback'];

        $output->writeln("  <info>Run webSocket on the $ip:$port.</>");
        $output->writeln("  You can use <info>CTRL+C</> to exit.");
        $output->writeln("  ... ...");

        $ws->startServer();
    }

    /**************************************************************************
     * 回调函数们
     **************************************************************************/

    public function userAddCallback(WebSocket $ws)
    {
        $count = count($ws->accept);

        $this->output->writeln("ADD: Now, connected user count: <info>$count</>");

        $this->sendToAll($count, 'num', $ws);
    }

    public function closeCallback(WebSocket $ws)
    {
        $count = count($ws->accept);

        $this->output->writeln("CLOSE: Now, connected user count: <info>$count</>");

        $this->sendToAll($count, 'num', $ws);
    }

    public function sendCallback($msg, $index, WebSocket $ws)
    {
        $data = json_encode(array(
            'text' => $msg,
            'user' => $index,
        ));

        $this->output->writeln("SEND: user [$index] send message: <info>$msg</>");

        $this->sendToAll($data, 'text', $ws);
    }

    public function sendToAll($data, $type, WebSocket $ws)
    {
        $res = array(
            'msg' => $data,
            'type' => $type,
        );

        $res = json_encode($res);
        $res = $ws->frame($res);

        foreach ($ws->accept as $key => $value) {
            socket_write($value, $res, strlen($res));
        }
    }
}